package scu.maqiang.mesh;

import java.util.HashSet;

import scu.maqiang.numeric.CG;
import scu.maqiang.numeric.UnorderIntArray;

public class Mesh2T10 extends Mesh {

	public Mesh2T10() {
		super();
		nDim = 2;
		nPerElement = 10;
		nPerBoundary = 4;
		nBoundaryPerElement = 3;
		nEdgePerElement = 9;
		nEdgePerBoundary = 3;
		tecplotType = "FETRIANGLE";
	}

	public Mesh2T10 square(int xNum, int yNum, T3Type tp) {
		int xNum3 = 3 * xNum;
		int yNum3 = 3 * yNum;
		nv = (xNum3 + 1) * (yNum3 + 1);
		nt = 2 * xNum * yNum;
		nb = 2 * (xNum + yNum);
		initMesh0(nv, nt, nb);
		int count = 0;
		for(int i = 0, m = yNum3 + 1; i < m; i++) {
			for(int j = 0, n = xNum3 + 1; j < n; j++) {
				nodes[count++] = new double[] {(j + 0.0) / xNum3, (i + 0.0) / yNum3};
			}
		}

		count = 0;
		for(int i = 0; i < yNum; i++) {
			for(int j = 0; j < xNum; j++) {
				int t1 = 3 * j + i * (xNum3 + 1);
				int t2 = t1 + 1;
				int t3 = t2 + 1;
				int t4 = t3 + 1;
				int t5 = t1 + xNum3 + 1;
				int t6 = t5 + 1;
				int t7 = t6 + 1;
				int t8 = t7 + 1;
				int t9 = t5 + xNum3 + 1;
				int t10 = t9 + 1;
				int t11 = t10 + 1;
				int t12 = t11 + 1;
				int t13 = t9 + xNum3 + 1;
				int t14 = t13 + 1;
				int t15 = t14 + 1;
				int t16 = t15 + 1;
				switch (tp) {
					case Left:
						elements[count++] = new int[] {t1, t4, t16, t2, t3, t8, t12, t11, t6, t7};
						elements[count++] = new int[] {t1, t16, t13, t6, t11, t15, t14, t9, t5, t10};
						break;
					case Right:
						elements[count++] = new int[] {t1, t4, t13, t2, t3, t7, t10, t9, t5, t6};
						elements[count++] = new int[] {t4, t16, t13, t8, t12, t15, t14, t10, t7, t11};
						break;
					case Cross1:
						if ((i + j) % 2 == 0) {
							elements[count++] = new int[] {t1, t4, t16, t2, t3, t8, t12, t11, t6, t7};
							elements[count++] = new int[] {t1, t16, t13, t6, t11, t15, t14, t9, t5, t10};
						} else {
							elements[count++] = new int[] {t1, t4, t13, t2, t3, t7, t10, t9, t5, t6};
							elements[count++] = new int[] {t4, t16, t13, t8, t12, t15, t14, t10, t7, t11};
						}
						break;
					case Cross2:
						if ((i + j) % 2 == 0) {
							elements[count++] = new int[] {t1, t4, t13, t2, t3, t7, t10, t9, t5, t6};
							elements[count++] = new int[] {t4, t16, t13, t8, t12, t15, t14, t10, t7, t11};
						} else {
							elements[count++] = new int[] {t1, t4, t16, t2, t3, t8, t12, t11, t6, t7};
							elements[count++] = new int[] {t1, t16, t13, t6, t11, t15, t14, t9, t5, t10};
						}
					default:
						throw new IllegalArgumentException("Unexpected T3Type!");
				}
			}
		}

		count = 0;
		for(int i = 0; i < xNum; i++) {
			int b1 = 3 * i;
			int b2 = b1 + 1;
			int b3 = b2 + 1;
			int b4 = b3 + 1;
			boundaries[count] = new int[] {b1, b4, b2, b3};
			boundaryLabel[count++] = 1;
		}

		for(int i = 0; i < yNum; i++) {
			int b1 = xNum3 + 3 * i * (xNum3 + 1);
			int b2 = b1 + xNum3 + 1;
			int b3 = b2 + xNum3 + 1;
			int b4 = b3 + xNum3 + 1;
			boundaries[count] = new int[] {b1, b4, b2, b3};
			boundaryLabel[count++] = 2;
		}

		for(int i = 0; i < xNum; i++) {
			int b1 = nv - 1 - i * 3;
			int b2 = b1 - 1;
			int b3 = b2 - 1;
			int b4 = b3 - 1;
			boundaries[count] = new int[] {b1, b4, b2, b3};
			boundaryLabel[count++] = 3;
		}

		for(int i = 0; i < yNum; i++) {
			int b1 = 3 * i * (xNum3 + 1);
			int b2 = b1 + xNum3 + 1;
			int b3 = b2 + xNum3 + 1;
			int b4 = b3 + xNum3 + 1;
			boundaries[count] = new int[] {b4, b1, b3, b2};
			boundaryLabel[count++] = 4;
		}

		return this;
	}
	
	@Override
	public double[] getinteriorPointInElement(double[][] coord) {
		return coord[9].clone();
	}

	@Override
	public double[] getinteriorPointOnBoundary(double[][] coord) {
		return coord[2].clone();
	}

	@Override
	public int[][] getBoundarysFromElement(int i) {
		int[][] boundarys = new int[nBoundaryPerElement][];
		int[] ele = elements[i];
		boundarys[0] = new int[] {ele[0], ele[1], ele[3], ele[4]};
		boundarys[1] = new int[] {ele[1], ele[2], ele[5], ele[6]};
		boundarys[2] = new int[] {ele[2], ele[0], ele[7], ele[8]};
		return boundarys;
	}

	@Override
	public boolean checkMesh(double[][] coord) {
		return CG.area2DT3(coord) > 0;
	}

	@Override
	public void setBoundaries(HashSet<UnorderIntArray> set) {
		this.nb = set.size();
		this.boundaries = new int[nb][];
		this.boundaryLabel = new int[nb];
		int count = 0;
		for(UnorderIntArray ele : set) {
			this.boundaries[count++] = ele.getIntSet();
		}
	}

	@Override
	public int getTecplotNt() {
		// TODO Auto-generated method stub
		return 9 * nt;
	}

	@Override
	public int[][] getEdgesFromElement(int i) {
		int[][] result = new int[9][];
		int[] ele = elements[i];
		result[0] = new int[] {ele[0], ele[3]};
		result[1] = new int[] {ele[3], ele[4]};
		result[2] = new int[] {ele[4], ele[1]};
		result[3] = new int[] {ele[1], ele[5]};
		result[4] = new int[] {ele[5], ele[6]};
		result[5] = new int[] {ele[6], ele[2]};
		result[6] = new int[] {ele[2], ele[7]};
		result[7] = new int[] {ele[7], ele[8]};
		result[8] = new int[] {ele[8], ele[0]};
		return result;
	}

}
